#include "stdio.h"
#include <stdlib.h>
#include <windows.h>
#include <string.h>

int main()
{
    system("chcp 65001");
#if 0
    // 对于文件读写,不就是学api,快速的占领这个知识领域,不要在这个地方领域,完成人生的财富知识库,
    // 横向学习-->快速的学习.
    // 打开fopen()
    // fopen(char *filename,char *type);
    //    "r"             打开，只读
    //    "w"             打开，文件指针指到头，只写
    //    "a"             打开，指向文件尾，在已存在文件中追加
    //    "rb"            打开一个二进制文件，只读
    //    "wb"            打开一个二进制文件，只写
    //    "ab"            打开一个二进制文件，进行追加
    //    "r+"            以读/写方式打开一个已存在的文件
    //    "w+"            以读/写方式建立一个新的文本文件
    //    "a+"            以读/写方式打开一个文件文件进行追加
    //    "rb+"           以读/写方式打开一个二进制文件
    //    "wb+"           以读/写方式建立一个新的二进制文件
    //    "ab+"           以读/写方式打开一个二进制文件进行追加

    FILE *fp = NULL;
    char *fname = "./11.txt";// -->build-07_-Desktop_Qt_5_11_1_MinGW_32bit-Debug/11.txt
    fp = fopen(fname,"w+");
    if (fp == NULL)
    {
        printf("func fopen() err: %s\n",fname);
        return -1;
    }
    if (fp != NULL)
    {
        fclose(fp);
    }
#endif
#if 0
    // fputc();字符读写
    FILE *fp = NULL;
    char a[100] = "^^^abcsmdjdsuoweoip";
    char *fname = "./1.txt";
    fp = fopen(fname,"a+");
    if(NULL == fp)
    {
        printf("func fopen() err: %s\n",fname);
        return -1;
    }
    for(int i = 0;i < strlen(a);i++)
    {
        fputc(a[i],fp);
    }

    if(fp != NULL)
    {
        fclose(fp);
    }
#endif
#if 0
    // 字符读
    FILE *fp = NULL;
    char a[] = {0};
    char *fname = "./1.txt";
    fp = fopen(fname,"r");
    if(NULL == fp)
    {
        printf("func fopen() err: %s\n",fname);
        return -1;
    }
    char tempCh;
    printf("[");
    while(!feof(fp))
    {
        tempCh = getc(fp);
        printf("%c",tempCh);
    }
    printf("]\n");
    if(fp != NULL)
    {
        fclose(fp);
    }
#endif
#if 0 // 按行读写
    // fputs()函数想指定文件写入一个由string指向的字符串，'\0'不写入文件。
    FILE *fp = NULL;
    char a[100] = "aaacvcvcvcdfgfggg";
    char *fname = "./88.txt";
    fp = fopen(fname,"r+");
    if(NULL == fp)
    {
        printf("func fopen() err: %s\n",fname);
        return -1;
    }
    fputs(a,fp);
    fputs("\n",fp);
    fputs(a,fp);
    if(fp != NULL)
    {
        fclose(fp);
    }
#endif
#if 0
    FILE *fp = NULL;
    char a[100];
    char *fname = "./88.txt";
    fp = fopen(fname,"r");
    if(NULL == fp)
    {
        printf("func fopen() err: %s\n",fname);
        return -1;
    }
    // 控制代码到每个函数,都能够执行完成.有日志.
    // 这个思想 _MaxCount:
    //fgets(char * __restrict__ _Buf,int _MaxCount,FILE * __restrict__ _File);
    char *p = NULL;
    while(!feof(fp))
    {
        p = fgets(a,100,fp);//100保证这个内存块不越界
        printf("%s \n",a);
        printf("%s \n",p);
    }
    printf("]\n");
    fputs(a,fp);
    if(fp != NULL)
    {
        fclose(fp);
    }
#endif
#if 0
    // rb :按照2机制文件,
    // 文件在磁盘上的存放有两种方式,Asi
    // 企业文件大多数都是不可见的
    // fgetc fputc 按照字符读写文件
    // fgets fputs 按照行读写文件
    // fread fwirte 按照块读写文件
#define SIZE 5
    typedef struct Student_
    {
        char name[10];
        int num;
        int age;
        char addr[15];
    }Student;
    int  i;
    FILE *fp = NULL;

    Student student[5];
    fp=fopen("./student.data","wb");
    if(fp == NULL)
    {
        printf("cannot open file\n");
        return;
    }

    for (i=0; i<5; i++)
    {
        memset(&student[i], 0, sizeof(Student));
        sprintf(student[i].name, "name%d", i+1);

        //把第二个参数组合的字符串，打印到第一个参数buf中。
        //sprintf(student[i].name,"name%d", i+1);
        //fprintf(fp,"name%d", i+1);
    }

    for(i=0;i<5;i++)
    {
        if(fwrite(&student[i],sizeof(Student),1,fp)!=1)
            printf("file write error\n");
    }

    fclose(fp);
    void display()
    {
        FILE *fp;
        int  i;

        Student student[SIZE];
        for (i=0; i<SIZE; i++)
        {
            memset(&student[i], 0, sizeof(Student));
            //sprintf(student[i].name, "name%d", i+1);
        }

        if((fp=fopen("./student.data","rb"))==NULL)
        {
            printf("cannot open file\n");
            return;
        }

        for(i=0;i<SIZE;i++)
        {
            fread(&student[i],sizeof(Student),1,fp);
            printf("%-10s %4d %4d %-15s\n",student[i].name,
                   student[i].num,student[i].age,student[i].addr);
        }
        fclose(fp);
    }
    display();
#endif
#if 0
    // 合理的界面分工
    // 1.现实中的业务模型,训练成一套api接口.
    // 1.界面显示:配置文件的集成,2.接口层:真正的完成配置文件读写.
    // -->1.写配置:参数->向什么地方写,写key,写valude
    // int WriteIniCfg(FILE* fp,char *key,char *value);// 往文件里写,不合理
    // int WriteFile(char *pfile,char *key,char *value);
    // -->2.读配置
    // -->3.修改配置
    // 1.分清楚功能
    // 2.分析出功能的输入和输出
    // 3.实现功能,兑现代码
    // 开发过程中:接口要求紧,模块要求松,各种模块之间要耦合低,该谁做就应该做.
    // 第1个和第3个-->
    // 下面这个,int type 参数就不应该漏出来,给A调用这个接口的人增加了技术含量.让写接口这个人判断是写还是修改

    // int WriteIniCfg(char *key,char *value,int type);// 1写2修改
    int WriteIniCfg(const char *pfile /*in*/,char *key /*in*/,char *valude /*in*/);
    int ReadIniCfg(const char *pfile,char *key,char *value);
    int ModifyIniCfg(const char *pfile,char *key,char *value);
#endif
#if 0 // 链表:是一种数据结构
    // 静态链表
    typedef struct _Teacher
    {
        char name[64];
        int age;
        struct _Teacher *next;
    }Teacher;

    Teacher t1,t2,t3;
    memset(&t1,0,sizeof(Teacher));
    memset(&t2,0,sizeof(Teacher));
    memset(&t3,0,sizeof(Teacher));
    t1.age = 11;
    t2.age = 22;
    t3.age = 33;
    t1.next = &t2;
    t2.next = &t3;
    t3.next = NULL;
    // 1.建立的时,指针指向谁,就把谁的地址赋给指针
    // 2. 赋值指针变量和业务操作之间的关系.
    // ==>看图说话
    Teacher *p = NULL;
    p = &t1;
    while(p)
    {
        printf("age:%d \n",p->age);
        p = p->next;
    }
    // 静态链表,在栈上分配的,有局限性.临时区,地址甩不出来,无形之中,就用成malloc了

#endif
#if 0
    // 链表应用场景:
#endif
#if 0
    // 链表概念: 1. 是个结构体 2. 两个域:指针域和data域 3.引用自身的结构体
    // 特点:非顺序存储
    // 分类:1.带头链表和不带头链表
    // 组织形式: 单向链表.双向链表,循环链表等
    // 静态链表少用,动态链表多用
    // 基本操作: 头结点pHead,当前结点pCurrent,前驱结点pPrior,后继结点pNext,
    // 编程关键点:指针指向谁,就把谁的地址赋给指针,code = diagram
    // 辅助指针变量&和操作逻辑的关系
    typedef struct  Node
    {
        int data;
        struct Node *next;
    }SLIST;

    //    SLIST *SList_Creat();
    //    int SListPrintf(SLIST *pHead);
    //    int SList_NodeInsert(SLIST *pHead,int x, int y);
    //    int SList_NodeDel(SLIST *pHead,int x);

    // 实现
    SLIST *SList_Creat()
    {
        // 1.创建头结点
        // 2.键盘输入数据,创建业务结点
        // 3.循环创建业务结点

        // 1.创建头结点,并初始化
        SLIST *pHead = NULL;
        pHead = (SLIST *)malloc(sizeof(SLIST));
        if(pHead == NULL)
            return -1;
        pHead->data = 0;
        pHead->next = NULL;

        // 2.键盘输入数据,创建业务结点
        int data = 0;
        printf("enter data :\n");
        scanf("%d",&data);

        // 3.循环创建业务结点

        SLIST *pTemp = NULL;
        SLIST *pCur = NULL;
        pCur = pHead;
        while(data != -1)
        {
            printf("data : [%d]\n",data);
            // 初始化
            pTemp = (SLIST *)malloc(sizeof(SLIST));
            if (pTemp == NULL)
            {
                return -1;
            }
            pTemp->data = data;
            pTemp->next = NULL;
            // 加入链表
            pCur->next = pTemp;
            // 让pCur 变成当前结点
            pCur = pTemp;// pCur = pCur->next;

            // 输入-1退出
            printf("enter value exet: -1 :\n");
            scanf("%d",&data);
        }
        return pHead;
    }
    int SListPrintf(SLIST *pHead)
    {
        if(pHead == NULL)
        {
            return -1;
        }

        SLIST *pTemp = NULL;
        pTemp = pHead->next;// 因为有头结点,头结点数据不需要保存
        int i = 1;
        while(pTemp)
        {
            printf("data[%d] : [%d]\n",i,pTemp->data);
            i++;
            pTemp = pTemp->next;
        }
        return 0;
    }

    int SList_NodeDel(SLIST *pHead,int x)
    {
        return 0;
    }

    int SList_Destory(SLIST *pHead)
    {
        // 因为链表是单向的,一下一个结点的位置,保存在前驱结点next域中,所以.
        // 删除节点之前,需要把后继结点给保存下来.
        if(pHead == NULL)
        {
            return 0;
        }

        SLIST *pTemp = NULL;
        SLIST *p= NULL;
        p = pHead;
        int i = 1;
        while(p)
        {
            printf("delet data[%d] : [%d]\n",i,p->data);
            i++;
            pTemp = p->next;
            free(p);
            p = pTemp;
        }
        return 0;
    }
    SLIST *pHead = NULL;
    pHead = SList_Creat();
    SListPrintf(pHead);
    SList_Destory(pHead);
#endif
#if 0
    // 链表的数据模型,链表业务模型和链表的逻辑操作,没有有效的分离.
    // 产生问题的本质原因,因为数据
    // 传统链表和非传统链表的区别
    // 数据域-->Node,就是业务结点,我们想通过业务结点把所有的业务数据包含了
    // 在现实中,数据区域太大了.
    // 我包含不了数据业务.我让业务结点包含我.
    typedef struct _node
    {
      struct _node *next;
    }node;
    // 我让结构体包含链表结点
    typedef struct Teacher
    {
        int age;
        // ...
        struct _node nead;
    }
    // 组织小链表的结点,就相当于组织小结构体的链表
#endif
#if 0
    // # ##
    // # 在宏函数体内,相当于创建一个字符串
#define STR(s) #s // #s将s的代码都变成字符串
    STR(assdfdfdf);
    printf("[%s]\n",STR(assdfdfdf));
    printf("[%s]\n",STR(main()));

    // ## 代表c token(编译器识别的最小单元) 的拼接,不是字符串的拼接,
    // 在vs下## ,vs和gcc 空格
    #define A(first,second)  first second
    printf("=============\n");
//    A(printf,("A [%s]\n","abc"));
    A(printf,("aaaa"));
#define ITCAST(a) itcast##a
//    int ITCAST(a) = 10;
    // itcast_a =10
//#deifne G(a) g##a
//    int G(value) = 10;
    // 可变参数
    #define showlist(...) \
        printf(#__VA_ARGS__)
    showlist(aaaa);
    showlist("([%s]assa\n)",aaaa);// 把所有参数都变成一个字符串
    #define compate(test,...) \
        (test)?(#test):printf(#__VA_ARGS__)
    int a = 10;
    int b = 20;
    compate(a>b,b is littlen);
#define DEBUGLOG(format,...) \
    fprintf(stderr,"[DEBUG][%s:%s,%d][%s][%s]"format,__FUNCTION__,__FILE__,__LINE__,__DATE__,__TIME__,##__VA_ARGS__);
    char *p = NULL;
    p = malloc(100);
    if(p == NULL)
    {
       fprintf(stderr,"[ERROR]p malloc error\n");
    }
    DEBUGLOG("a=%d,b= %d\n",a,b);

#endif
#if 1
    // valgrind
#endif
    return 0;
}
